/*
 * Copyright (c) Jiandong.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import { AssetManager } from './AssetManager';
import { LifecycleEventListener } from './LifecycleEventListener';
import { JavaScriptContextHolder } from '../bridge/JavaScriptContextHolder';
import HashSet from '@ohos.util.HashSet';
import { NativeModule } from '../bridge/NativeModule';
import { JavaScriptModule } from '../bridge/JavaScriptModule';
import { MessageQueueThread } from '../bridge/queue/MessageQueueThread';
import { ReactQueueConfiguration } from '../bridge/queue/ReactQueueConfiguration';
import { CatalystInstance } from '../bridge/CatalystInstance';

export class ReactContext {
  private static readonly TAG = "ReactContext";
  private mContext: any
  private mCatalystInstance: CatalystInstance;
  private mUiMessageQueueThread: MessageQueueThread;
  private mNativeModulesMessageQueueThread: MessageQueueThread;
  private mJSMessageQueueThread: MessageQueueThread;
  private mIsInitialized: boolean;
  private mDestroyed: boolean

  public constructor(context: any) {
    //      this.mLifecycleState = LifecycleState.BEFORE_CREATE;
    this.mContext = context;
    this.mDestroyed = false;
    this.mIsInitialized = false;
  }

  public initializeWithInstance(catalystInstance: CatalystInstance) {
    if (catalystInstance == null) {
      throw Error("CatalystInstance cannot be null.");
    } else if (this.mCatalystInstance != null) {
      throw Error("ReactContext has been already initialized");
    } else {
      if (this.mDestroyed) {
        throw Error("Cannot initialize ReactContext after it has been destroyed.");
      }

      this.mCatalystInstance = catalystInstance;
      let queueConfig: ReactQueueConfiguration = catalystInstance.getReactQueueConfiguration();
      this.initializeMessageQueueThreads(queueConfig);
    }
  }

  public initializeMessageQueueThreads(queueConfig: ReactQueueConfiguration) {
    //        FLog.w("ReactContext", "initializeMessageQueueThreads() is called.");
    if (this.mUiMessageQueueThread == null && this.mNativeModulesMessageQueueThread == null && this.mJSMessageQueueThread == null) {
      this.mUiMessageQueueThread = queueConfig.getUIQueueThread();
      this.mNativeModulesMessageQueueThread = queueConfig.getNativeModulesQueueThread();
      this.mJSMessageQueueThread = queueConfig.getJSQueueThread();
      if (this.mUiMessageQueueThread == null) {
        throw new Error("UI thread is null");
      } else if (this.mNativeModulesMessageQueueThread == null) {
        // todo , should support NativeModules thread???
        //throw new Error("NativeModules thread is null");
      } else if (this.mJSMessageQueueThread == null) {
        throw new Error("JavaScript thread is null");
      } else {
        this.mIsInitialized = true;
      }
    } else {
      throw new Error("Message queue threads already initialized");
    }
  }

  public getAppName(): string {
    return ""
  }

  public getFilesDir():string {
    return ""
  }

  public getAssets(): AssetManager {
    return new AssetManager()
  }

  //    public void resetPerfStats() {
  //        if (this.mNativeModulesMessageQueueThread != null) {
  //            this.mNativeModulesMessageQueueThread.resetPerfStats();
  //        }
  //
  //        if (this.mJSMessageQueueThread != null) {
  //            this.mJSMessageQueueThread.resetPerfStats();
  //        }
  //
  //    }

  //    public setJSExceptionHandler(jSExceptionHandler: JSExceptionHandler) {
  //        this.mJSExceptionHandler = jSExceptionHandler;
  //    }

  public getNativeModules(): HashSet<NativeModule> {
    if (this.mCatalystInstance == null) {
      this.raiseCatalystInstanceMissingException();
    }
    return this.mCatalystInstance.getNativeModules();
  }

  //    public Object getSystemService(String name) {
  //        if ("layout_inflater".equals(name)) {
  //            if (this.mInflater == null) {
  //                this.mInflater = LayoutInflater.from(this.getBaseContext()).cloneInContext(this);
  //            }
  //
  //            return this.mInflater;
  //        } else {
  //            return this.getBaseContext().getSystemService(name);
  //        }
  //    }

  //    public  getJSModule<T extends JavaScriptModule>(jsInterface: Class<T> ): T {
  //        if (this.mCatalystInstance == null) {
  //            if (this.mDestroyed) {
  //                throw new Error("Tried to access a JS module after the React instance was destroyed.");
  //            } else {
  //                throw new Error("Tried to access a JS module before the React instance was fully set up. Calls to ReactContext#getJSModule should only happen once initialize() has been called on your native module.");
  //            }
  //        } else {
  //            return this.mCatalystInstance.getJSModule(jsInterface);
  //        }
  //    }

  //    public  hasNativeModule<T extends NativeModule>(nativeModuleInterface: Class<T> ): boolean {
  //        if (this.mCatalystInstance == null) {
  //            this.raiseCatalystInstanceMissingException();
  //        }
  //
  //        return this.mCatalystInstance.hasNativeModule(nativeModuleInterface);
  //    }

  public getCatalystInstance(): CatalystInstance {
    return this.mCatalystInstance;
    //        return (CatalystInstance)Assertions.assertNotNull(this.mCatalystInstance);
  }

  //    @Nullable
  //    public  getNativeModule<T extends NativeModule>(nativeModuleInterface：Class<T>): T | ? {
  //        if (this.mCatalystInstance == null) {
  //            this.raiseCatalystInstanceMissingException();
  //        }
  //
  //        return this.mCatalystInstance.getNativeModule(nativeModuleInterface);
  //    }

  //
  public addLifecycleEventListener(listener: LifecycleEventListener): void {
    //this.mCatalystInstance.get


    //        this.mLifecycleEventListeners.add(listener);
    //        if (this.hasActiveReactInstance() || this.isBridgeless()) {
    //            switch(this.mLifecycleState) {
    //            case BEFORE_CREATE:
    //            case BEFORE_RESUME:
    //                break;
    //            case RESUMED:
    //                this.runOnUiQueueThread(new Runnable() {
    //                    public void run() {
    //                        if (ReactContext.this.mLifecycleEventListeners.contains(listener)) {
    //                            try {
    //                                listener.onHostResume();
    //                            } catch (RuntimeException var2) {
    //                                ReactContext.this.handleException(var2);
    //                            }
    //
    //                        }
    //                    }
    //                });
    //                break;
    //            default:
    //                throw new IllegalStateException("Unhandled lifecycle state.");
    //            }
    //        }

  }
  //
  //    /** @deprecated */
  //    @Deprecated
  //    public boolean hasActiveCatalystInstance() {
  //        return this.hasActiveReactInstance();
  //    }
  //
  //    public boolean hasActiveReactInstance() {
  //        return this.mCatalystInstance != null && !this.mCatalystInstance.isDestroyed();
  //    }
  //
  //    public boolean hasCatalystInstance() {
  //        return this.mCatalystInstance != null;
  //    }
  //
  //    public LifecycleState getLifecycleState() {
  //        return this.mLifecycleState;
  //    }

  //    @ThreadConfined("UI")
  public onHostPause() {
    //        this.mLifecycleState = LifecycleState.BEFORE_RESUME;
    //        ReactMarker.logMarker(ReactMarkerConstants.ON_HOST_PAUSE_START);
    //        Iterator var1 = this.mLifecycleEventListeners.iterator();
    //
    //        while(var1.hasNext()) {
    //            LifecycleEventListener listener = (LifecycleEventListener)var1.next();
    //
    //            try {
    //                listener.onHostPause();
    //            } catch (RuntimeException var4) {
    //                this.handleException(var4);
    //            }
    //        }
    //
    //        ReactMarker.logMarker(ReactMarkerConstants.ON_HOST_PAUSE_END);
  }
  //
  //    public void removeLifecycleEventListener(LifecycleEventListener listener) {
  //        this.mLifecycleEventListeners.remove(listener);
  //    }
  //
  //    public void addActivityEventListener(ActivityEventListener listener) {
  //        this.mActivityEventListeners.add(listener);
  //    }
  //
  //    public void removeActivityEventListener(ActivityEventListener listener) {
  //        this.mActivityEventListeners.remove(listener);
  //    }
  //
  //    public void addWindowFocusChangeListener(WindowFocusChangeListener listener) {
  //        this.mWindowFocusEventListeners.add(listener);
  //    }
  //
  //    public void removeWindowFocusChangeListener(WindowFocusChangeListener listener) {
  //        this.mWindowFocusEventListeners.remove(listener);
  //    }

  //    @ThreadConfined("UI")
  //    public void onHostResume(Activity activity) {
  //        this.mLifecycleState = LifecycleState.RESUMED;
  //        this.mCurrentActivity = new WeakReference(activity);
  //        ReactMarker.logMarker(ReactMarkerConstants.ON_HOST_RESUME_START);
  //        Iterator var2 = this.mLifecycleEventListeners.iterator();
  //
  //        while(var2.hasNext()) {
  //            LifecycleEventListener listener = (LifecycleEventListener)var2.next();
  //
  //            try {
  //                listener.onHostResume();
  //            } catch (RuntimeException var5) {
  //                this.handleException(var5);
  //            }
  //        }
  //
  //        ReactMarker.logMarker(ReactMarkerConstants.ON_HOST_RESUME_END);
  //    }


  //    @ThreadConfined("UI")
  //    public void onNewIntent(@Nullable Activity activity, Intent intent) {
  //        UiThreadUtil.assertOnUiThread();
  //        this.mCurrentActivity = new WeakReference(activity);
  //        Iterator var3 = this.mActivityEventListeners.iterator();
  //
  //        while(var3.hasNext()) {
  //            ActivityEventListener listener = (ActivityEventListener)var3.next();
  //
  //            try {
  //                listener.onNewIntent(intent);
  //            } catch (RuntimeException var6) {
  //                this.handleException(var6);
  //            }
  //        }
  //
  //    }

  //    @ThreadConfined("UI")
  public onHostDestroy() {
    //        UiThreadUtil.assertOnUiThread();
    //        this.mLifecycleState = LifecycleState.BEFORE_CREATE;
    //        Iterator var1 = this.mLifecycleEventListeners.iterator();
    //
    //        while(var1.hasNext()) {
    //            LifecycleEventListener listener = (LifecycleEventListener)var1.next();
    //
    //            try {
    //                listener.onHostDestroy();
    //            } catch (RuntimeException var4) {
    //                this.handleException(var4);
    //            }
    //        }
    //
    //        this.mCurrentActivity = null;
  }

  //    @ThreadConfined("UI")
  public destroy() {
    //        UiThreadUtil.assertOnUiThread();
    this.mDestroyed = true;
    if (this.mCatalystInstance != null) {
      this.mCatalystInstance.destroy();
    }

  }

  /** @deprecated */
  public isBridgeless(): boolean {
    return false;
  }
  //
  //    public void onActivityResult(Activity activity, int requestCode, int resultCode, @Nullable Intent data) {
  //        Iterator var5 = this.mActivityEventListeners.iterator();
  //
  //        while(var5.hasNext()) {
  //            ActivityEventListener listener = (ActivityEventListener)var5.next();
  //
  //            try {
  //                listener.onActivityResult(activity, requestCode, resultCode, data);
  //            } catch (RuntimeException var8) {
  //                this.handleException(var8);
  //            }
  //        }
  //
  //    }
  //
  //    @ThreadConfined("UI")
  //    public void onWindowFocusChange(boolean hasFocus) {
  //        UiThreadUtil.assertOnUiThread();
  //        Iterator var2 = this.mWindowFocusEventListeners.iterator();
  //
  //        while(var2.hasNext()) {
  //            WindowFocusChangeListener listener = (WindowFocusChangeListener)var2.next();
  //
  //            try {
  //                listener.onWindowFocusChange(hasFocus);
  //            } catch (RuntimeException var5) {
  //                this.handleException(var5);
  //            }
  //        }
  //
  //    }
  //
  //    public void assertOnUiQueueThread() {
  //        ((MessageQueueThread)Assertions.assertNotNull(this.mUiMessageQueueThread)).assertIsOnThread();
  //    }
  //
  //    public boolean isOnUiQueueThread() {
  //        return ((MessageQueueThread)Assertions.assertNotNull(this.mUiMessageQueueThread)).isOnThread();
  //    }
  //
  //    public void runOnUiQueueThread(Runnable runnable) {
  //        ((MessageQueueThread)Assertions.assertNotNull(this.mUiMessageQueueThread)).runOnQueue(runnable);
  //    }
  //
  //    public void assertOnNativeModulesQueueThread() {
  //        if (!this.mIsInitialized) {
  //            throw new IllegalStateException("Tried to call assertOnNativeModulesQueueThread() on an uninitialized ReactContext");
  //        } else {
  //            ((MessageQueueThread)Assertions.assertNotNull(this.mNativeModulesMessageQueueThread)).assertIsOnThread();
  //        }
  //    }
  //
  //    public void assertOnNativeModulesQueueThread(String message) {
  //        if (!this.mIsInitialized) {
  //            throw new IllegalStateException("Tried to call assertOnNativeModulesQueueThread(message) on an uninitialized ReactContext");
  //        } else {
  //            ((MessageQueueThread)Assertions.assertNotNull(this.mNativeModulesMessageQueueThread)).assertIsOnThread(message);
  //        }
  //    }
  //
  //    public boolean isOnNativeModulesQueueThread() {
  //        return ((MessageQueueThread)Assertions.assertNotNull(this.mNativeModulesMessageQueueThread)).isOnThread();
  //    }

  //    public void runOnNativeModulesQueueThread(Runnable runnable) {
  //        ((MessageQueueThread)Assertions.assertNotNull(this.mNativeModulesMessageQueueThread)).runOnQueue(runnable);
  //    }
  //
  //    public void assertOnJSQueueThread() {
  //        ((MessageQueueThread)Assertions.assertNotNull(this.mJSMessageQueueThread)).assertIsOnThread();
  //    }
  //
  //    public boolean isOnJSQueueThread() {
  //        return ((MessageQueueThread)Assertions.assertNotNull(this.mJSMessageQueueThread)).isOnThread();
  //    }
  //
  //    public boolean runOnJSQueueThread(Runnable runnable) {
  //        return ((MessageQueueThread)Assertions.assertNotNull(this.mJSMessageQueueThread)).runOnQueue(runnable);
  //    }
  //
  //    public void handleException(Exception e) {
  //        boolean catalystInstanceVariableExists = this.mCatalystInstance != null;
  //        boolean isCatalystInstanceAlive = catalystInstanceVariableExists && !this.mCatalystInstance.isDestroyed();
  //        boolean hasExceptionHandler = this.mJSExceptionHandler != null;
  //        if (isCatalystInstanceAlive && hasExceptionHandler) {
  //            this.mJSExceptionHandler.handleException(e);
  //        } else {
  //            FLog.e("ReactNative", "Unable to handle Exception - catalystInstanceVariableExists: " + catalystInstanceVariableExists + " - isCatalystInstanceAlive: " + !isCatalystInstanceAlive + " - hasExceptionHandler: " + hasExceptionHandler, e);
  //            throw new IllegalStateException(e);
  //        }
  //    }
  //
  //    public JSExceptionHandler getExceptionHandler() {
  //        if (this.mExceptionHandlerWrapper == null) {
  //            this.mExceptionHandlerWrapper = new ReactContext.ExceptionHandlerWrapper();
  //        }
  //
  //        return this.mExceptionHandlerWrapper;
  //    }
  //
  //    public boolean hasCurrentActivity() {
  //        return this.mCurrentActivity != null && this.mCurrentActivity.get() != null;
  //    }
  //
  //    public boolean startActivityForResult(Intent intent, int code, Bundle bundle) {
  //        Activity activity = this.getCurrentActivity();
  //        if (activity != null) {
  //            activity.startActivityForResult(intent, code, bundle);
  //            return true;
  //        } else {
  //            return false;
  //        }
  //    }
  //
  //    @Nullable
  //    public Activity getCurrentActivity() {
  //        return this.mCurrentActivity == null ? null : (Activity)this.mCurrentActivity.get();
  //    }

  //    @Nullable
  public getSourceURL(): string | null {
    return this.mCatalystInstance.getSourceURL();
  }

  //    public getJavaScriptContextHolder(): JavaScriptContextHolder {
  //        return this.mCatalystInstance.getJavaScriptContextHolder();
  //    }

  //    @Nullable
  //    public JSIModule getJSIModule(JSIModuleType moduleType) | null {
  //        if (!this.hasActiveReactInstance()) {
  //            throw new IllegalStateException("Unable to retrieve a JSIModule if CatalystInstance is not active.");
  //        } else {
  //            return this.mCatalystInstance.getJSIModule(moduleType);
  //        }
  //    }

  //
  private raiseCatalystInstanceMissingException() {
    throw new Error(this.mDestroyed ? "Trying to call native module after CatalystInstance has been destroyed!" : "Trying to call native module before CatalystInstance has been set!");
  }

  //    public void registerSegment(int segmentId, String path, Callback callback) {
  //        ((CatalystInstance)Assertions.assertNotNull(this.mCatalystInstance)).registerSegment(segmentId, path);
  //        ((Callback)Assertions.assertNotNull(callback)).invoke(new Object[0]);
  //    }
  //
  //    public class ExceptionHandlerWrapper implements JSExceptionHandler {
  //        public ExceptionHandlerWrapper() {
  //        }
  //
  //        public void handleException(Exception e) {
  //            ReactContext.this.handleException(e);
  //        }
  //    }
}
